package com.example.game_logic;

import android.util.Log;

import com.example.game_logic.Color.ColorID;

/**
 * Cette classe abstraite est une definition general de ce
 * qu'est un bloc dans la grille de jeu
 **/
public class Bloc{
	public enum Cardinality {
		North, South, East, West, None
	}
	
	protected int[] coord_;
	
	protected boolean isUsed_;
	protected boolean isExtremity_;
	
	protected Bloc blocParent_;
	protected Bloc blocChild_;
	
	protected Line line_;
	
	// Constructeur par position
	public Bloc(int x, int y, boolean isExtremity)
	{
		blocParent_ = null;
		blocChild_ = null;
		line_ = null;
		coord_ = new int[2];
		coord_[0] = x;
		coord_[1] = y;
		isUsed_ = false;
		isExtremity_ = isExtremity;
	}
	
	/* Ajouter un enfant
	 * 
	 * Si le bloc courant a deja un enfant il est enleve
	 * 
	 * Si le bloc enfant n'est pas adjacent il n'est pas
	 * ajoute et les enfants du bloc courant ne sont pas
	 * enleves
	 */
	public boolean addChild(Bloc enfant)
	{
		// On verifie que le bloc est adjacent
		if ( !isBlocAdjacent(enfant) )
		{
			// TODO : ajout d'un algo de completion de chemin
			return false;
		}
		
		// Cas ou on retourne au parent de la ligne
		if (line_.getStartBloc().isSameBloc(enfant))
		{
			return false;
		}
		
		// Cas ou l'enfant est un bloc extremite d'une autre ligne
		if (enfant.isExtremity() && enfant.getLine() != line_)
		{
			return false;
		}
		
		// Cas ou l'enfant est deja dans la ligne
		if (enfant.getLine() == line_ && !enfant.isExtremity())
		{
			enfant.removeChildren();
			return true;
		}
		
		// On verifie que le bloc courant n'avait pas deja des enfants
		// ??necessaire??
		if (blocChild_ != null)
		{
			removeChildren();
		}
		
		blocChild_ = enfant;
		blocChild_.setParent(this);	
		return true;
	}

	/*
	 * Le parent du bloc courant devient le bloc en parametre
	 */
	protected boolean setParent(Bloc parent)
	{
		// Cas ou Extremite etant le debut de la ligne
		if (parent == null && isExtremity_)
		{
			blocParent_ = null;
			isUsed_ = true;
			return true;
		}		
		
		// On verifie si le bloc avait deja un parent
		// S'il en avait un on enleve ses enfants
		if (blocParent_ != null)
		{
			blocParent_.removeChildren();
		}
		
		blocParent_ = parent;
		isUsed_ = true;
		
		setLine(blocParent_.getLine());
		
		return true;
	}
	
	/* Enlever les enfants du blocs courant
	 * 
	 * Cela consiste a elever recursivement tous les blocs
	 * attaches au bloc courant.
	 * 
	 * Les blocs enleves sont remis a une color null et
	 * n'ont plus de parent et/ou d'enfant 
	 */
	public void removeChildren()
	{
		if (blocChild_ == null)
		{
			return;
		}
		
		blocChild_.detachFromParent();
		blocChild_ = null;
	}
	
	/* Methode detachant un bloc et ses enfants du bloc parent
	 * 
	 * Le bloc courant et ses enfants sont tous dissocies	 * 
	 */
	protected void detachFromParent()
	{
		blocParent_ = null;
		isUsed_ = false;
		removeChildren();
		
		setLine(null);
	}
	
	/* Verifie si le bloc est adjacent au bloc courant
	 * 
	 * Si le bloc est immediatement adjacent au nord, au sud,
	 * a est ou a ouest la methode retourne true sinon false
	 */
	public boolean isBlocAdjacent(Bloc bloc)
	{
		int[] blocCoord = new int[2];
		blocCoord = bloc.getCoord();
		
		int difX = blocCoord[0] - coord_[0];
		int difY = blocCoord[1] - coord_[1];
		double dist = Math.pow(difX, 2.0) + Math.pow(difY, 2.0);
		
		if ( dist == 1.0 )
		{
			return true;
		}
		
		return false;
	}
	
	public boolean isUsed()
	{
		return isUsed_;
	}
	
	public void setUnused()
	{
		if (blocParent_ != null)
		{
			detachFromParent();
		}
		if (blocChild_ != null)
		{
			removeChildren();
		}
		
		setLine(null);
		
		isUsed_ = false;
	}
	
	public int[] getCoord()
	{
		return coord_;
	}
	
	public Line getLine()
	{
		return line_;
	}
	
	public boolean setLine(Line line)
	{
		if (line_ != null && isExtremity_)
		{
			return false;
		}
		
		line_ = line;
		return true;
	}
	
	public Bloc getParent()
	{
		return blocParent_;
	}
	
	public Bloc getChild()
	{
		return blocChild_;		
	}
	
	public boolean isExtremity()
	{
		return isExtremity_;
	}
	
	public boolean isSameBloc(Bloc bloc)
	{
		int[] coord = bloc.getCoord();
		if (coord[0] == coord_[0] && coord[1] == coord_[1])
		{
			return true;
		}
		
		return false;
	}
	
	public ColorID getColor()
	{
		if (line_ == null)
		{
			return ColorID.EMPTY;
		}
		return line_.getColor();
	}
	
	public void setStartBloc()
	{
		if (!isExtremity_)
			return;
		
		line_.setStartBloc(this);
	}
	
	public Cardinality getParentCard()
	{
		if (blocParent_ == null)
			return Cardinality.None;
		
		return getBlocCard(blocParent_);
	}
	
	public Cardinality getChildCard()
	{
		if (blocChild_ == null)
			return Cardinality.None;
		
		return getBlocCard(blocChild_);
	}
	
	private Cardinality getBlocCard(Bloc bloc)
	{
		int[] coord = bloc.getCoord();
		int diffY = coord_[0] - coord[0];
		int diffX = coord_[1] - coord[1];
		
		if (!isBlocAdjacent(bloc))
			return Cardinality.None;
		
		if (diffX == 1)
		{
			return Cardinality.North;
		}
		if (diffX == -1)
		{
			return Cardinality.South;
		}
		if (diffY == 1)
		{
			return Cardinality.West;
		}
		if (diffY == -1)
		{
			return Cardinality.East;
		}
		
		return Cardinality.None;
		
		
	}

}
